package com.zmn.oms.business.impl.work;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.math.MathUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.oms.business.interfaces.work.OrderWorkPositionBService;
import com.zmn.oms.common.constant.OrderLogConsts;
import com.zmn.oms.common.constant.OrderPayConsts;
import com.zmn.oms.common.dro.orderpay.OrderPayResultDRO;
import com.zmn.oms.common.dto.OmsBaseOperator;
import com.zmn.oms.model.bo.work.OrderWorkPositionBO;
import com.zmn.oms.model.dto.work.position.OrderWorkPositionManualSyncDIO;
import com.zmn.oms.model.entity.detail.OrderDetail;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.model.entity.work.OrderWorkPosition;
import com.zmn.oms.model.vo.work.OrderWorkPositionVO;
import com.zmn.oms.services.interfaces.detail.OrderDetailService;
import com.zmn.oms.services.interfaces.work.OrderWorkPositionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @author sunlife
 * @date:2020/8/17 5:03 下午
 * description:
 */
@Slf4j
@Service
public class OrderWorkPositionBServiceImpl implements OrderWorkPositionBService {

    private static final List<Integer> SYNC_TYPE_LIST = Lists.newArrayList(OrderLogConsts.ORDER_LOG_TYPE_INPUT, OrderLogConsts.ORDER_LOG_TYPE_UPDATE,
            OrderLogConsts.ORDER_LOG_TYPE_CONFIRM, OrderLogConsts.ORDER_LOG_TYPE_MASTER_LEAVE, OrderLogConsts.ORDER_LOG_TYPE_VISIT,
            OrderLogConsts.ORDER_LOG_TYPE_MASTER_IMAGE, OrderLogConsts.ORDER_LOG_TYPE_PAY, OrderLogConsts.ORDER_LOG_TYPE_COMPLETE);

    @Autowired
    private OrderWorkPositionService orderWorkPositionService;
    @Autowired
    private OrderDetailService orderDetailService;

    @Override
    public OrderWorkPositionVO getById(Long positionId) {
        if (NumberUtil.isNullOrZero(positionId)) {
            return null;
        }
        OrderWorkPosition position = orderWorkPositionService.findById(positionId);
        if (position != null) {
            return BeanMapper.map(position, OrderWorkPositionVO.class);
        }
        return null;
    }

    @Override
    public int updateById(OrderWorkPositionBO bo) {
        if (NumberUtil.isNullOrZero(bo.getWorkId())) {
            return 0;
        }

        OrderWorkPosition currOrderWorkPosition = BeanMapper.map(bo, OrderWorkPosition.class);
        currOrderWorkPosition.setPositionId(currOrderWorkPosition.getWorkId());

        OrderWorkPosition orderWorkPosition = orderWorkPositionService.findById(bo.getWorkId());
        if (orderWorkPosition == null) {
            currOrderWorkPosition.setCreater(currOrderWorkPosition.getUpdater());
            currOrderWorkPosition.setCreateTime(currOrderWorkPosition.getUpdateTime());
            return orderWorkPositionService.insert(currOrderWorkPosition);
        } else {
            return orderWorkPositionService.updateById(currOrderWorkPosition);
        }
    }

    @Override
    @Transactional
    public void syncOrderPosition(OrderWork orderWork, OmsBaseOperator omsBaseOperator, int logType) {
        if (!SYNC_TYPE_LIST.contains(logType)) {
            return;
        }

        Double longitude = omsBaseOperator.getLongitude(), latitude = omsBaseOperator.getLatitude();

        if (longitude == null || latitude == null || longitude == 0D) {
            if (!Objects.equals(OrderLogConsts.ORDER_LOG_TYPE_PAY, logType)){
                return;
            }

            OrderPayResultDRO orderPayResultDRO = (OrderPayResultDRO) omsBaseOperator;
            if (!Objects.equals(OrderPayConsts.ORDER_PAY_MASTER, orderPayResultDRO.getAmountType())) {
                return;
            }

            // 尾款支付完成，支付位置处理，如果没有位置信息，需要去工程师验收时的位置
            this.manualSyncMasterPayPositionByMasterPayLocation(orderWork);

            return;
        }

        OrderWorkPositionBO bo = new OrderWorkPositionBO();

        Long workId = omsBaseOperator.getWorkId();
        bo.setWorkId(workId);
        bo.setOrderId(omsBaseOperator.getWorkId());
        bo.setUpdater(omsBaseOperator.getOperator());
        bo.setUpdateTime(new Date());

        if (Objects.equals(OrderLogConsts.ORDER_LOG_TYPE_INPUT, logType) || Objects.equals(OrderLogConsts.ORDER_LOG_TYPE_UPDATE, logType) ||Objects.equals(OrderLogConsts.ORDER_LOG_TYPE_CONFIRM, logType)) {
            // 新增、修改、确认
            bo.setOrderLatitude(latitude);
            bo.setOrderLongitude(longitude);
        } else if (Objects.equals(OrderLogConsts.ORDER_LOG_TYPE_MASTER_LEAVE, logType)) {
            // 出发
            bo.setStartLatitude(latitude);
            bo.setStartLongitude(longitude);
            bo.setStartDistance(calcDistance(workId, longitude, latitude, bo));
        } else if (Objects.equals(OrderLogConsts.ORDER_LOG_TYPE_VISIT, logType)) {
            // 上门
            bo.setVisitLatitude(latitude);
            bo.setVisitLongitude(longitude);
            bo.setVisitDistance(calcDistance(workId, longitude, latitude, bo));
//            CommunityDTO visitCommunityInfo = this.getVisitCommunityInfo(longitude, latitude);
//            bo.setVisitCommunityId(visitCommunityInfo.getCommunityId());
//            bo.setVisitCommunityName(visitCommunityInfo.getName());
        } else if (Objects.equals(OrderLogConsts.ORDER_LOG_TYPE_PAY, logType)) {
            // 支付 - 定金支付、师傅收款
            OrderPayResultDRO orderPayResultDRO = (OrderPayResultDRO) omsBaseOperator;
            //定金
            if (Objects.equals(OrderPayConsts.ORDER_PAY_DEPOSIT, orderPayResultDRO.getAmountType())) {
                bo.setDepositPayLatitude(latitude);
                bo.setDepositPayLongitude(longitude);
                bo.setDepositPayDistance(calcDistance(workId, longitude, latitude, bo));
            } else if (Objects.equals(OrderPayConsts.ORDER_PAY_MASTER, orderPayResultDRO.getAmountType())) {
                bo.setMasterPayLatitude(latitude);
                bo.setMasterPayLongitude(longitude);
                bo.setMasterPayDistance(customerMinPayDistance(workId, orderWork.getVisitUserId(), longitude, latitude));
            }
            OrderDetail orderDetail = orderDetailService.findOrderDetailByKeySrcMaster(workId);
            if (orderDetail != null) {
                bo.setOrderLongitude(orderDetail.getLongitude());
                bo.setOrderLatitude(orderDetail.getLatitude());
            }
        } else if (Objects.equals(OrderLogConsts.ORDER_LOG_TYPE_COMPLETE, logType)) {
            // 完成
            bo.setCompleteLatitude(latitude);
            bo.setCompleteLongitude(longitude);
            bo.setCompleteDistance(customerCalcDistance(workId, orderWork.getVisitUserId(), longitude, latitude));
        } else if (Objects.equals(OrderLogConsts.ORDER_LOG_TYPE_MASTER_IMAGE, logType)) {
            // 工程师形象照
            bo.setMasterImageLatitude(latitude);
            bo.setMasterImageLongitude(longitude);
            bo.setMasterImageDistance(calcDistance(workId, longitude, latitude, bo));
        }

        this.updateById(bo);
    }

    private Integer calcDistance(Long workId, Double longitude, Double latitude, OrderWorkPositionBO bo) {
        if (Objects.isNull(longitude) || Objects.isNull(latitude) || longitude == 0D) {
            return null;
        }

        OrderDetail orderDetail = orderDetailService.findOrderDetailByKeySrcMaster(workId);
        if (orderDetail != null) {
            bo.setOrderLongitude(orderDetail.getLongitude());
            bo.setOrderLatitude(orderDetail.getLatitude());
        }

        double distance = MathUtil.GetDistance(orderDetail.getLongitude(), orderDetail.getLatitude(), longitude, latitude);
        return ((Long)Math.round(distance)).intValue();
    }

    @Override
    public Integer customerCalcDistance(Long workId, Long visitUserId, Double longitude, Double latitude) {
        if (Objects.isNull(longitude) || Objects.isNull(latitude) || longitude == 0D) {
            return null;
        }

        // 用户家的位置：优先取上门扫码时的位置>上传形象照的位置>用户下单的地址
        OrderDetail orderDetail = orderDetailService.findOrderDetailByKeySrcMaster(workId);
        OrderWorkPosition orderWorkPosition = Optional.ofNullable(orderWorkPositionService.findById(workId)).orElse(new OrderWorkPosition());
        Double homeLongitude = 0D;
        Double homeLatitude = 0D;
        if (orderWorkPosition.getVisitDistance() != null && NumberUtil.isNotNullOrZero(visitUserId)) {
            homeLongitude = orderWorkPosition.getVisitLongitude();
            homeLatitude = orderWorkPosition.getVisitLatitude();
        } else if (orderWorkPosition.getMasterImageDistance() != null) {
            homeLongitude = orderWorkPosition.getMasterImageLongitude();
            homeLatitude = orderWorkPosition.getMasterImageLatitude();
        } else {
            homeLongitude = orderDetail.getLongitude();
            homeLatitude = orderDetail.getLatitude();
        }

        double distance = MathUtil.GetDistance(homeLongitude, homeLatitude, longitude, latitude);
        return ((Long)Math.round(distance)).intValue();
    }

    @Override
    public Integer customerMinPayDistance(Long workId, Long visitUserId, Double longitude, Double latitude) {
        return this.customerMinPayDistance(workId, visitUserId, longitude, latitude, null);
    }

    @Override
    public Integer customerMinPayDistance(Long workId, Long visitUserId, Double longitude, Double latitude, OrderWorkPosition orderWorkPosition) {
        if (Objects.isNull(longitude) || Objects.isNull(latitude) || longitude == 0D) {
            return null;
        }

        // 用户家的位置：取上门扫码时的位置/上传形象照的位置/用户下单的地址 距离最小的
        orderWorkPosition = Optional.ofNullable(orderWorkPosition).orElse(orderWorkPositionService.findById(workId));
        if (Objects.isNull(orderWorkPosition)) {
            return null;
        }

        List<Double> distanceList = Lists.newArrayListWithExpectedSize(3);
        if (NumberUtil.isNotNullOrZero(visitUserId) && orderWorkPosition.getVisitDistance() != null && orderWorkPosition.getVisitLongitude() != null) {
            double distance = MathUtil.GetDistance(orderWorkPosition.getVisitLongitude(), orderWorkPosition.getVisitLatitude(), longitude, latitude);
            distanceList.add(distance);
            log.info("上门扫码用户支付距离判断：{},{} {},{} 支付距离:{}", orderWorkPosition.getVisitLongitude(), orderWorkPosition.getVisitLatitude(), longitude, latitude, distance);
        }
        if (orderWorkPosition.getMasterImageDistance() != null) {
            double distance = MathUtil.GetDistance(orderWorkPosition.getMasterImageLongitude(), orderWorkPosition.getMasterImageLatitude(), longitude, latitude);
            distanceList.add(distance);
            log.info("形象照距离判断：{},{} {},{} 支付距离:{}", orderWorkPosition.getVisitLongitude(), orderWorkPosition.getVisitLatitude(), longitude, latitude, distance);
        }
        if (orderWorkPosition.getOrderLongitude() != null) {
            double distance = MathUtil.GetDistance(orderWorkPosition.getOrderLongitude(), orderWorkPosition.getOrderLatitude(), longitude, latitude);
            distanceList.add(distance);
            log.info("工单地址距离判断：{},{} {},{} 支付距离:{}", orderWorkPosition.getOrderLongitude(), orderWorkPosition.getOrderLatitude(), longitude, latitude, distance);
        }

        double distance = distanceList.stream().min(Comparator.comparing(Double::valueOf)).get();
        log.info("工单[{}]支付距离检查：{}, 最小距离：{}", workId, JSON.toJSONString(distanceList), distance);
        return ((Long) Math.round(distance)).intValue();
    }

    @Override
    public void manualSyncMasterPayLocation(OrderWork orderWork, OrderWorkPositionManualSyncDIO dio) {
        if (dio.getLongitude() == null || dio.getLatitude() == null || dio.getLongitude() == 0D) {
            return;
        }

        Double longitude = dio.getLongitude(),latitude = dio.getLatitude();

        OrderWorkPosition currOrderWorkPosition = new OrderWorkPosition();
        currOrderWorkPosition.setPositionId(orderWork.getWorkId());
        currOrderWorkPosition.setOrderId(orderWork.getOrderId());
        currOrderWorkPosition.setWorkId(orderWork.getWorkId());
        currOrderWorkPosition.setUpdateTime(new Date());
        currOrderWorkPosition.setUpdater(dio.getOperator());
        currOrderWorkPosition.setMasterPayLatitude(latitude);
        currOrderWorkPosition.setMasterPayLongitude(longitude);
        OrderWorkPosition orderWorkPosition = orderWorkPositionService.findById(orderWork.getWorkId());
        if (orderWorkPosition == null) {
           return;
        }

        if (orderWorkPosition.getMasterPayDistance() == null) {
            log.info("工单[{}] manualSyncMasterPayLocation：{}", orderWork.getWorkId(), JSON.toJSONString(currOrderWorkPosition));
            orderWorkPositionService.updateById(currOrderWorkPosition);
        }
    }

    /**
     * 根据工程师支付位置更新距离
     * @param orderWork
     */
    private void manualSyncMasterPayPositionByMasterPayLocation(OrderWork orderWork) {
        OrderWorkPosition orderWorkPosition = orderWorkPositionService.findById(orderWork.getWorkId());
        if (orderWorkPosition == null) {
            return;
        }

        OrderWorkPosition currOrderWorkPosition = new OrderWorkPosition();
        currOrderWorkPosition.setPositionId(orderWork.getWorkId());
        currOrderWorkPosition.setOrderId(orderWork.getOrderId());
        currOrderWorkPosition.setWorkId(orderWork.getWorkId());
        currOrderWorkPosition.setUpdateTime(new Date());
        // 获取最小支付距离
        Integer minPayDistance = this.customerMinPayDistance(orderWork.getWorkId(), orderWork.getVisitUserId(),
                orderWorkPosition.getMasterPayLongitude(), orderWorkPosition.getMasterPayLatitude(), orderWorkPosition);
        currOrderWorkPosition.setMasterPayDistance(minPayDistance);

        log.info("工单[{}] manualSyncMasterPayPositionByMasterPayLocation：{}", orderWork.getWorkId(), JSON.toJSONString(currOrderWorkPosition));
        orderWorkPositionService.updateById(currOrderWorkPosition);
    }

    @Override
    @Transactional
    public void manualSyncOrderPayPosition(OrderWork orderWork, OrderWorkPositionManualSyncDIO dio) {

        if (dio.getLongitude() == null || dio.getLatitude() == null || CollectionUtil.isNullOrEmpty(dio.getLogTypes()) || dio.getLongitude() == 0D) {
            return;
        }

        Double longitude = dio.getLongitude(),latitude = dio.getLatitude();

        OrderWorkPositionBO bo = new OrderWorkPositionBO();

        Long workId = orderWork.getWorkId();
        bo.setWorkId(workId);
        bo.setOrderId(orderWork.getWorkId());
        bo.setUpdateTime(new Date());
        bo.setUpdater(dio.getOperator());

        List<Integer> logTypes = dio.getLogTypes();

        // 获取最小支付距离
        Integer minPayDistance = customerMinPayDistance(workId, orderWork.getVisitUserId(), longitude, latitude);

        if (logTypes.contains(OrderLogConsts.ORDER_LOG_TYPE_PAY)) {
            bo.setMasterPayLatitude(latitude);
            bo.setMasterPayLongitude(longitude);
            bo.setMasterPayDistance(minPayDistance);
        }
        if (logTypes.contains(OrderLogConsts.ORDER_LOG_TYPE_COMPLETE)) {
            // 完成
            bo.setCompleteLatitude(latitude);
            bo.setCompleteLongitude(longitude);
            bo.setCompleteDistance(minPayDistance);
        }

        log.info("工单[{}] manualSyncOrderPayPosition：{}", orderWork.getWorkId(), JSON.toJSONString(bo));

        this.updateById(bo);
    }
}
